package dao

import (
	"errors"
	"fmt"
	"go.uber.org/zap"
	"gorm.io/gorm"
	"kf/models/entity"
	"kf/utils"
	"strconv"
	"strings"
)

type SysRoleDao struct {
	DB           *gorm.DB
	UserRolesDao *SysUserRolesDao
	Log          *zap.Logger
}

func (sysRoleDao *SysRoleDao) Option() []utils.Option[uint64] {
	var options []utils.Option[uint64]
	var sysRoles []entity.SysRole
	sysRoleDao.DB.Select("id,name").Find(&sysRoles)
	for _, role := range sysRoles {
		var option utils.Option[uint64]
		option.Label = role.Name
		option.Value = role.ID
		options = append(options, option)
	}
	return options
}

// 分页获取数据
func (sysRoleDao *SysRoleDao) GetRolePage(queryParams entity.PageQuery) (utils.Page[entity.SysRole], error) {
	var totalRecords int64
	page := *queryParams.PageNum      // 当前页码
	pageSize := *queryParams.PageSize // 每页数据量

	// 计算偏移量
	offset := (page - 1) * pageSize
	var roles []entity.SysRole
	var res utils.Page[entity.SysRole]
	db := sysRoleDao.DB.Model(&entity.SysRole{})

	if queryParams.Keywords != nil && *queryParams.Keywords != "" {
		db.Where("code like ? or name like ?", "%"+*queryParams.Keywords+"%", "%"+*queryParams.Keywords+"%")
	}
	err := db.Offset(int(offset)).Limit(int(pageSize)).Find(&roles).Error
	if err != nil {
		return res, err
	}
	// 获取总记录数
	err = sysRoleDao.DB.Model(&entity.SysRole{}).Count(&totalRecords).Error
	if err != nil {
		return res, err
	}
	res.List = roles
	res.Total = totalRecords
	return res, nil
}

// 根据id查询角色
func (sysRoleDao *SysRoleDao) GetRoleForm(id int64) (entity.RoleForm, error) {
	var roleForm entity.RoleForm
	err := sysRoleDao.DB.Model(&entity.SysRole{}).Where("id = ?", id).First(&roleForm).Error
	if err != nil {
		return roleForm, err
	}
	return roleForm, nil
}

// 保存角色
func (sysRoleDao *SysRoleDao) SaveRole(form entity.RoleForm) (bool, error) {
	// 编辑角色时，判断角色是否存在
	var oldRole entity.SysRole
	if form.ID != 0 {
		result := sysRoleDao.DB.Model(&entity.SysRole{}).Where("id = ?", form.ID).First(&oldRole)
		if errors.Is(result.Error, gorm.ErrRecordNotFound) {
			return false, errors.New("角色不存在")
		} else if result.Error != nil {
			return false, result.Error
		}
	}
	var count int64
	db := sysRoleDao.DB.Model(&entity.SysRole{})
	if form.ID != 0 {
		db.Where("id <> ?", form.ID)
	}
	err := db.Where("(code = ? or name =?)", form.Code, form.Name).Count(&count).Error
	if err != nil {
		return false, err
	}
	if count > 0 {
		sysRoleDao.Log.Error("角色名称或角色编码已存在，请修改后重试！")
		return false, errors.New("角色名称或角色编码已存在，请修改后重试！")
	}

	sysRole := entity.SysRole{
		Model: entity.Model{
			ID: form.ID,
		},
		Name:      form.Name,
		Code:      form.Code,
		Sort:      form.Sort,
		Status:    form.Status,
		DataScope: form.DataScope,
	}

	if form.ID == 0 {
		err := sysRoleDao.DB.Model(&entity.SysRole{}).Save(&sysRole).Error
		if err != nil {
			return false, err
		}
	} else {
		err := sysRoleDao.DB.Model(&entity.SysRole{}).Select("name", "code", "sort", "status", "data_scope").
			Where("id = ?", form.ID).
			Updates(&sysRole).Error
		if err != nil {
			return false, err
		}
	}
	return true, nil
}

// 根据id获取数据
func (sysRoleDao *SysRoleDao) GetRoleById(id uint64) (entity.SysRole, error) {
	var sysRole entity.SysRole
	result := sysRoleDao.DB.Model(&entity.SysRole{}).Where("id = ?", id).First(&sysRole)
	if errors.Is(result.Error, gorm.ErrRecordNotFound) {
		return sysRole, errors.New("角色不存在")
	} else if result.Error != nil {
		return sysRole, result.Error
	}
	return sysRole, nil
}

func (sysRoleDao *SysRoleDao) DeleteRoles(ids string) (bool, error) {
	err := sysRoleDao.DB.Transaction(func(tx *gorm.DB) error {
		if ids == "" {
			return errors.New("至少需要一个参数")
		}
		split := strings.Split(ids, ",")
		var list []uint64
		for _, val := range split {
			end, _ := strconv.ParseUint(val, 10, 64)
			list = append(list, end)
		}
		for _, roleId := range list {
			sysRole, err := sysRoleDao.GetRoleById(roleId)
			if err != nil {
				return err
			}
			count, err := sysRoleDao.UserRolesDao.HasAssignedUsers(roleId)
			if err != nil {
				return err
			}
			if count {
				return errors.New("角色【" + sysRole.Name + "】已分配用户，请先解除关联后删除")
			}
			err = sysRoleDao.DB.Delete(&entity.SysRole{}, "id = ?", roleId).Error
			if err != nil {
				return err
			}
		}
		return nil
	})
	if err != nil {
		return false, err
	} else {
		return true, nil
	}
}

// 权限分配
func (sysRoleDao *SysRoleDao) GetRoleMenuIds(id string) ([]uint64, error) {
	sql := `SELECT
            rm.menu_id
        FROM
            sys_role_menu rm
                INNER JOIN sys_menu m ON rm.menu_id = m.id
        WHERE
            rm.role_id =` + id
	var ids []uint64
	err := sysRoleDao.DB.Raw(sql).Find(&ids).Error
	if err != nil {
		sysRoleDao.Log.Error("查询权限分配报错", zap.Error(err))
		return ids, err
	}
	return ids, nil
}

func (sysRoleDao *SysRoleDao) AssignMenusToRole(idStr string, ids []uint64) (b bool, e error) {
	db := sysRoleDao.DB.Begin()
	defer func() {
		if r := recover(); r != nil {
			db.Rollback() // 捕获panic，确保回滚
			fmt.Println("Recovered in safeCall", r)
			b = false
			e = errors.New("执行报错")
		}
	}()
	var sysRole entity.SysRole
	err := db.Model(&entity.SysRole{}).Where("id = ?", idStr).Find(&sysRole).Error
	if err != nil {
		db.Rollback()
		sysRoleDao.Log.Error("查询报错", zap.Error(err))
		return false, errors.New("角色不存在")
	}
	err = db.Delete(&entity.SysRoleMenu{}, "role_id = ?", idStr).Error
	if err != nil {
		db.Rollback()
		sysRoleDao.Log.Error("删除角色菜单失败", zap.Error(err))
		return false, errors.New("删除角色菜单失败")
	}
	//批量创建角色菜单
	var roleMenus []entity.SysRoleMenu
	for _, id := range ids {
		menu := entity.SysRoleMenu{
			RoleId: sysRole.ID,
			MenuId: id,
		}
		roleMenus = append(roleMenus, menu)
	}
	err = db.Model(&entity.SysRoleMenu{}).CreateInBatches(&roleMenus, 100).Error
	if err != nil {
		db.Rollback()
		sysRoleDao.Log.Error("批量保存角色菜单失败", zap.Error(err))
		return false, errors.New("批量保存角色菜单失败")
	}
	db.Commit()
	return true, nil
}
